import { VuexModule, Module, Action, Mutation, getModule } from 'vuex-module-decorators'
import { login, logout, getUserInfo, refreshToken, getAllResource } from '@/api/users'
import { getToken, setToken, removeToken, setRefreshToken, getRefreshToken, removeRefreshToken } from '@/utils/cookies'
import router, { resetRouter } from '@/router'
import { PermissionModule } from './permission'
// import { TagsViewModule } from './tags-view'
import store from '@/store'

export interface IUserState {
  token: string
  name: string
  avatar: string
  introduction: string
  roles: string[]
  email: string
}

@Module({ dynamic: true, store, name: 'user', namespaced: true })
class User extends VuexModule implements IUserState {
  public token = getToken() || ''
  public refreshToken = getRefreshToken() || ''
  public id = ''
  public name = ''
  public avatar = ''
  public introduction = ''
  public roles: string[] = []
  public email = ''
  public tenant = ''
  private resources:Array<string> = []

  get ID() {
    return this.id
  }

  get AVATAR() {
    return this.avatar
  }

  get RESOURCES() {
    return this.resources
  }

  @Mutation
  private SET_ID(id: string) {
    this.id = id
  }

  @Mutation
  private SET_RESOURCE(resources: Array<string>) {
    this.resources = resources
  }

  @Mutation
  private SET_TOKEN(token: string) {
    this.token = token
  }

  @Mutation
  private SET_REFRESH_TOKEN(token: string) {
    this.refreshToken = token
  }

  @Mutation
  private SET_NAME(name: string) {
    this.name = name
  }

  @Mutation
  private SET_AVATAR(avatar: string) {
    this.avatar = avatar
  }

  @Mutation
  private SET_INTRODUCTION(introduction: string) {
    this.introduction = introduction
  }

  @Mutation
  private SET_ROLES(roles: string[]) {
    this.roles = roles
  }

  @Mutation
  private SET_EMAIL(email: string) {
    this.email = email
  }

  @Mutation
  private SET_TENANT(tenant: string) {
    this.tenant = tenant
  }

  @Action
  public async Login(userInfo: { username: string, password: string, captcha: string, captchaKey: string}) {
    let { username, password, captcha, captchaKey } = userInfo
    username = username.trim()
    let _this = this
    const res: any = await login({ username, password, captcha, captchaKey, grant_type: 'password', scope: 'all' })
    if (res.expires_in < 1 * 3600) {
      const rt: any = await refreshToken(res.refresh_token)
      _this.SET_TOKEN(rt.access_token)
      _this.SET_REFRESH_TOKEN(rt.refresh_token)
      setToken(rt.access_token)
      setRefreshToken(rt.refresh_token)
    } else {
      setToken(res.access_token)
      setRefreshToken(res.refresh_token)
      this.SET_TOKEN(res.access_token)
      this.SET_REFRESH_TOKEN(res.refresh_token)
    }
    this.GetUserInfo()
  }

  @Action
  public ResetToken() {
    removeToken()
    removeRefreshToken()
    this.SET_TOKEN('')
    this.SET_REFRESH_TOKEN('')
    this.SET_ROLES([])
  }

  @Action
  public async GetUserInfo() {
    if (this.token === '') {
      throw Error('GetUserInfo: token is undefined!')
    }
    const { data } = await getUserInfo({ /* Your params here */ })
    if (!data) {
      throw Error('Verification failed, please Login again.')
    }

    const { id, authorities, name, tenantId, roles } = data
    // roles must be a non-empty array
    if (!authorities || authorities.length <= 0) {
      throw Error('GetUserInfo: roles must be a non-null array!')
    }
    this.SET_ID(id)
    this.SET_ROLES(roles)
    this.SET_NAME(name)
    this.SET_TENANT(tenantId)
    // this.ChangeRoles()
    this.loadUserResource()
  }

  @Action
  public loadUserResource() {
    getAllResource().then((res: any) => {
      if (res.data) {
        this.SET_RESOURCE(<Array<string>> res.data)
        PermissionModule.GenerateRoutesForResource(this.RESOURCES)
        resetRouter()
        // Add generated routes
        router.addRoutes(PermissionModule.dynamicRoutes)

        // Reset visited views and cached views
        // TagsViewModule.delAllViews()
      }
    })
  }

  @Action
  public ChangeRoles() {
    resetRouter()
    // Generate dynamic accessible routes based on roles
    PermissionModule.GenerateRoutes(this.roles)
    // Add generated routes
    router.addRoutes(PermissionModule.dynamicRoutes)

    // Reset visited views and cached views
    // TagsViewModule.delAllViews()
  }

  @Action
  public async LogOut() {
    if (this.token === '') {
      throw Error('LogOut: token is undefined!')
    }
    // await logout()
    this.ResetToken()
    resetRouter()
  }
}

export const UserModule = getModule(User)
